﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YmtSystem.CrossCutting;
using YmtAuth.Common;
using YmtAuth.Common.Utility;
using YmtAuth.Domain.Model.User;
using YmtAuth.Domain.Shard;
using MongoDB.Bson.Serialization.Attributes;
using YmtAuth.Domain.DomainService;
using MongoDB.Bson.Serialization.Options;
using Ymatou.User.Dto;
using YmtAuth.Dto;
using Ymatou.User.Dto.Auth;
using MongoDB.Bson;
using YmtSystem.Infrastructure.EventBusService;
using YmtAuth.Domain.EventHistory;

namespace YmtAuth.Domain.Model.LoginAuth
{
    /// <summary>
    /// 用户凭据管理
    /// </summary>
    public class UserLoginBill : Entity<string>
    {
        [BsonElement("uId")]
        public int UserId { get; set; }
        [BsonElement("lPas")]
        public string LoginPassword { get; set; }
        [BsonElement("lBills")]
        public Bills LoginBills { get; set; }
        public bool Locked { get; set; }
        [BsonIgnoreIfNull]
        public string Token { get; set; }
        [BsonElement("cDate")]
        public DateTime CreateDate { get; set; }
        [BsonElement("mDate")]
        public DateTime ModifyDate { get; set; }
        [BsonElement("tPas")]
        [BsonIgnoreIfNull]
        public string TradingPassword { get; set; }
        [BsonIgnore]
        public string RegSource { get; set; }
        //注：这个字段是为了兼容，在认证库登录失败，但在码头登录成功的用户（在APP集成认证服务之后，删除该字段）
        [BsonIgnore]
        public bool IsYmtLogin { get; set; }
        /// <summary>
        /// 根据uData数据容器生成用户登录票据
        /// </summary>      
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public UserLoginBill(Dictionary<string, object> uData, int userId = -1)
        {
            //TODO:使用 factory 或 创建者模式 重构
            YmtSystemAssert.AssertArgumentNotNull(uData, "用户数据集不能为空");
            //get data
            var uid = Convert.ToInt32(uData.TryGetV(YmtUserKey.uId, YmtUserKey.uId_Inval));
            var pas = uData.TryGetV(YmtUserKey.sPassword, null) as string;

            var pas2 = uData.TryGetV(YmtUserKey.sPassword2, "1") as string;
            var tradingPas = uData.TryGetV(YmtUserKey.sTradingPassword, null) as string;
            var loginId = uData.TryGetV(YmtUserKey.sLoginId, null) as string;
            var loginEmail = uData.TryGetV(YmtUserKey.sLoginEmail, null) as string;
            var loginMobile = uData.TryGetV(YmtUserKey.sMobile, null) as string;
            var rtype = uData.TryGetV(YmtUserKey.rType, YmtUserKey.rType_def_Val);
            var token = uData.TryGetV(YmtUserKey.sToken, null) as string;
            var import = uData.TryGetV(YmtUserKey.sDataImport, null) as string;
            var userSource = uData.TryGetV(YmtUserKey.sUserSource, "0") as string;
            var locked = uData.TryGetV(YmtUserKey.bLocked, false);
            var isYmtLogin = uData.TryGetV(YmtUserKey.IsYmtLogin, false).ConvertTo(false);
            if (string.IsNullOrEmpty(pas.ToString()))
                throw new ArgumentNullException("登录密码不能为空 不能为空");

            var uSource = Convert.ToInt32(userSource).ConvertTo<UserSource>();

            //if (userId != -1)
            //    uid = userId;

            if (uid == YmtUserKey.uId_Inval)
                throw new ArgumentException("无效的用户ID");

            RegSource = uSource.ToString();
            Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
            UserId = uid;

            SetUserLoginPassword(pas, import, uSource, isYmtLogin);
            CreateDate = DateTime.Now;
            ModifyDate = DateTime.Now;
            Token = token;
            Locked = locked.ConvertTo<bool>(false);
            TradingPassword = string.IsNullOrEmpty(import) ? string.IsNullOrEmpty(tradingPas) ? null : YmtEncryptTradingPassword(tradingPas) : tradingPas;
            LoginBills = new Bills(loginId, loginEmail, loginMobile, false/*!(uSource == UserSource.Weibo || uSource == UserSource.Alipay || uSource == UserSource.QQ || !string.IsNullOrEmpty(import) || isYmtLogin)*/);
            IsYmtLogin = isYmtLogin;
        }

        private void SetUserLoginPassword(string loginPas, string import, UserSource userSource, bool isYmtLogin = false)
        {

            if (userSource == UserSource.Alipay || userSource == UserSource.QQ || userSource == UserSource.Weibo)
            {
                LoginPassword = "8ymatou.com";
                return;
            }
            if (IsYmtLogin) LoginPassword = loginPas;
            else
                LoginPassword = string.IsNullOrEmpty(import) ? YmtEncryptUserPassword(loginPas) : loginPas;
        }

        /// <summary>
        ///  设置登录ID
        /// </summary>    
        public void ChangLoginId(string loginId)
        {
            if (string.IsNullOrEmpty(loginId) || DefaultBills.EmptyLoginId == loginId) return;
            //YmtSystemAssert.AssertArgumentNotEmpty(loginId, "loginId 不能为空");
            if (this.LoginBills == null)
                this.LoginBills = new Bills(null, null, null);
            this.LoginBills.SetLoginId(loginId);

            ModifyDate = DateTime.Now;
        }

        /// <summary>
        ///  验证并改变密码
        /// </summary>
        /// <exception cref="ArgumentException"></exception>
        /// <param name="pas"></param>
        /// <param name="pasType"></param>
        public ResetPasswordReponseCode ChangPassword(string newPas, PasswordActionType pasType, string oldPas, string clientIp = null, string clientType = null)
        {
            if (pasType == PasswordActionType.ModifyLoginPassword)
            {
                return this.ChangLoginPassword(newPas, oldPas, clientIp, clientType);
            }
            else if (pasType == PasswordActionType.ModifyTradingPassword)
            {
                return this.ChangTradingPassword(newPas, oldPas, clientIp, clientType);
            }
            else throw new ArgumentException("错误的pasType");
        }

        /// <summary>
        ///  设置登录邮箱
        /// </summary>    
        public void ChangLoginEmail(string email)
        {
            if (string.IsNullOrEmpty(email)) return;
            
            if (this.LoginBills == null)
                this.LoginBills = new Bills(null, null, null);
            this.LoginBills.SetLoginEmail(email);

            ModifyDate = DateTime.Now;

        }

        /// <summary>
        ///  设置登录手机
        /// </summary>    
        public void ChangLoginMobile(string mobile)
        {
            if (string.IsNullOrEmpty(mobile)) return;
            if (this.LoginBills == null)
                this.LoginBills = new Bills(null, null, null);
            this.LoginBills.SetLoginMobile(mobile, false);

            ModifyDate = DateTime.Now;

        }
   
        /// <summary>
        ///  设置用户登录token
        /// </summary>       
//        public void SetLoginToken(int userType, string loginTime = "")
//        {
//            if (string.IsNullOrEmpty(loginTime))
//                loginTime = DateTime.Now.ToString("yyyyMMddHHmmss");
//            this.Token = LoginKeyTypeService.EncryptCookieToken(this.UserId, userType, loginTime);
//            this.ModifyDate = DateTime.Now;
//        }

        /// <summary>
        ///  验证登录密码
        /// </summary>      
        public bool CheckLoginPassword(string loginPassword)
        {
            YmtSystemAssert.AssertArgumentNotEmpty(loginPassword, "登录密码不能为空");
            if (DefaultBills.EmptyPassword == loginPassword) return true;
            return this.LoginPassword == YmtEncryptUserPassword(loginPassword);
        }

        /// <summary>
        ///  验证交易密码
        /// </summary>      
        public bool CheckTradingPassword(string tradingPassword)
        {
            YmtSystemAssert.AssertArgumentNotEmpty(tradingPassword, "交易密码不能为空");
            return this.TradingPassword == YmtEncryptTradingPassword(tradingPassword);
        }

        /// <summary>
        /// 锁定凭据
        /// </summary>
        public void SetLocked(bool locked = true)
        {
            this.Locked = locked;
            this.ModifyDate = DateTime.Now;
        }

        /// <summary>
        /// 解除锁定
        /// </summary>
        public void UnLocked()
        {
            this.Locked = false;
            this.ModifyDate = DateTime.Now;
        }

        public bool IsLocked()
        {
            return this.Locked == true;
        }
        /// <summary>
        ///  检查交易密码是否等同登录密码
        /// </summary>       
        public bool CheckTradingPasswordEqualsLoginPassword(string tradingPassword)
        {
            if (tradingPassword == null) return false;
            return YmtEncryptUserPassword(tradingPassword).Equals(this.LoginPassword, StringComparison.CurrentCulture);
        }

        /// <summary>
        /// 当前实体转为Dictionary，兼容之前提供给dms，app 使用
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, object> ToDictionary()
        {
            return new Dictionary<string, object>
            {
               {YmtUserKey.sLoginId,this.LoginBills.LoginId},
               {YmtUserKey.sTradingPassword,this.TradingPassword},
               {YmtUserKey.uId,this.UserId},
               {YmtUserKey.sLoginEmail,this.LoginBills.Email},
               {YmtUserKey.sToken,this.Token},
               {YmtUserKey.sMobile,this.LoginBills.Mobile}
            };
        }

        public UserLoginBills AsUserLoginBills(string sign = null)
        {
            return new UserLoginBills
            {
                UserId = this.UserId,
                LoginId = this.LoginBills.LoginId,
                LoginMail = this.LoginBills.Email,
                LoginMobile = this.LoginBills.Mobile,
                TradingPassword = this.TradingPassword,
                Sign = sign
            };
        }

        /// <summary>
        /// 检查用户凭据是否满足登录条件 （密码检查及用户状态）
        /// </summary>
        /// <param name="pas"></param>
        /// <returns></returns>
        public ResponseData<LoginAuthResponseDto2> CheckUserAllowLogin(string pas,string loginId)
        {
            //密码空，或错误，禁止登陆
            if (string.IsNullOrEmpty(pas))
                return
                    ResponseData<LoginAuthResponseDto2>.CreateFail(
                        new LoginAuthResponseDto2 { UserData = new UserLoginBills(), Code = LoginResponseCode.LoingIdOrPasError },
                        "0", "登录密码不能为空");
            if (this.LoginPassword != YmtEncryptUserPassword(pas))
            {
                YmatouLoggingService.Debug("用户登录密码错误，{0}", loginId);
                return
                    ResponseData<LoginAuthResponseDto2>.CreateFail(
                        new LoginAuthResponseDto2 {UserData = new UserLoginBills(),Code = LoginResponseCode.LoingIdOrPasError},"0",
                         "用户名或登录密码错误");
            }
            //被锁定，禁止登陆
            if (this.IsLocked())
            {
                YmatouLoggingService.Debug("用户 {0}被锁定", this.LoginBills.LoginId);
                return
                    ResponseData<LoginAuthResponseDto2>.CreateFail(
                        new LoginAuthResponseDto2 { UserData = new UserLoginBills(), Code = LoginResponseCode.UserLocked }
                        ,"6",  "用户被锁定");
            }
            return
                ResponseData<LoginAuthResponseDto2>.CreateSuccess(
                    new LoginAuthResponseDto2
                    {
                        UserData =
                            new UserLoginBills
                            {
                                UserId = this.UserId,
                                LoginId = this.LoginBills.LoginId,
                                LoginMail = this.LoginBills.Email,
                                LoginMobile = this.LoginBills.Mobile,
                                TradingPassword = this.TradingPassword
                            },
                        Code = LoginResponseCode.OK
                    },  "ok");
        }
        /// <summary>
        /// 登录名长度检查
        /// </summary>
        /// <param name="loginId"></param>
        /// <returns></returns>
        public static ResponseData<LoginAuthResponseDto2> CheckLoginId(string loginId)
        {
            if (string.IsNullOrEmpty(loginId))
            {
                return ResponseData<LoginAuthResponseDto2>.CreateFail(new LoginAuthResponseDto2 { Code = LoginResponseCode.NullLoingId, UserData = new UserLoginBills { } }, lastErrorMessage: "非法的登录名");
            }
            if (!loginId.Contains("@") && Encoding.Default.GetBytes(loginId).Length >= BillVerifySpecifications.MaxLoginIdLength)
            {
                return ResponseData<LoginAuthResponseDto2>.CreateFail(new LoginAuthResponseDto2 { Code = LoginResponseCode.InvalidLoingId, UserData = new UserLoginBills { } }, lastErrorMessage: "非法的登录名");
            }
            return ResponseData<LoginAuthResponseDto2>.CreateSuccess(new LoginAuthResponseDto2 { });
        }
        /// <summary>
        /// 设置交易密码
        /// </summary>       
        private ResetPasswordReponseCode ChangTradingPassword(string newTpas, string oldTPas, string clientIp = null, string clientType = null)
        {
            //如果是系统默认密码则不修改密码
            if (string.IsNullOrEmpty(newTpas) || DefaultBills.EmptyPassword == newTpas)
                return ResetPasswordReponseCode.Success;

            if (!string.IsNullOrEmpty(oldTPas) && !this.CheckTradingPassword(oldTPas))
                return ResetPasswordReponseCode.OldPasswordError;
            //检查交易密码与登录密码是否一致
            if (this.LoginPassword == YmtEncryptUserPassword(newTpas))
                return ResetPasswordReponseCode.TradingPasEqualLoginPas;
            this.TradingPassword = YmtEncryptTradingPassword(newTpas);
            ModifyDate = DateTime.Now;
            EventBus.Instance.Publish<YmtUserPasswordChangeEvent>(new YmtUserPasswordChangeEvent(this.UserId, this.LoginBills.LoginId, string.IsNullOrEmpty(oldTPas) ? null : YmtEncryptTradingPassword(oldTPas), this.TradingPassword, clientIp, clientType, "tpas"));
            return ResetPasswordReponseCode.Success;
        }
        /// <summary>
        ///  修改密码        
        /// </summary>
        /// <exception cref="ArgumentNullException"></exception>
        private ResetPasswordReponseCode ChangLoginPassword(string newLoginPassword, string oldLoginPassword, string clientIp = null, string clientType = null)
        {
            //如果是系统默认密码，或者密码为空 则不修改密码
            if (string.IsNullOrEmpty(newLoginPassword) || DefaultBills.EmptyPassword == newLoginPassword)
                return ResetPasswordReponseCode.Success;

            YmtSystemAssert.AssertArgumentNotEmpty(newLoginPassword, "密码不能为空");
            if (this.LoginPassword != "8ymatou.com" && !string.IsNullOrEmpty(oldLoginPassword) && !this.CheckLoginPassword(oldLoginPassword))
                return ResetPasswordReponseCode.OldPasswordError;
            if (newLoginPassword.Length < 6) return ResetPasswordReponseCode.NewPasswordLenthLt6;
                       
            //检查登录密码与交易密码是否一致
            if (this.TradingPassword == YmtEncryptTradingPassword(newLoginPassword))
                return ResetPasswordReponseCode.LoginPasEqualTradingPas;
            this.LoginPassword = YmtEncryptUserPassword(newLoginPassword);           
            ModifyDate = DateTime.Now;
            EventBus.Instance.Publish<YmtUserPasswordChangeEvent>(new YmtUserPasswordChangeEvent(this.UserId, this.LoginBills.LoginId, string.IsNullOrEmpty(oldLoginPassword) ? null : YmtEncryptUserPassword(oldLoginPassword), this.LoginPassword, clientIp, clientType, "lpas"));
            return ResetPasswordReponseCode.Success;
        }

//        public void SetLoginPassword(string newLoginPassword)
//        {
//            if (string.IsNullOrEmpty(newLoginPassword)) throw new ArgumentNullException("初始化登录密码不能为空");
//            this.LoginPassword = this.YmtEncryptUserPassword(newLoginPassword);
//        }
//        public void SetTradingPassword(string newTradingPassword)
//        {
//            if (string.IsNullOrEmpty(newTradingPassword)) throw new ArgumentNullException("初始化交易密码不能为空");
//            this.LoginPassword = this.YmtEncryptTradingPassword(newTradingPassword);
//        }

        public Tuple<LoginResponseCode, string> CheckUserToken(string token)
        {
            if (string.IsNullOrEmpty(token)) return Tuple.Create(LoginResponseCode.TokenInvalid, "token无效");
            if (IsLocked()) return Tuple.Create(LoginResponseCode.UserLocked, "用户被锁定");
            if (token != this.Token) return Tuple.Create(LoginResponseCode.TokenInvalid, "token 不匹配");
            return Tuple.Create(LoginResponseCode.OK, "ok");
        }
        /// <summary>
        /// 登录密码加密
        /// </summary>       
        private string YmtEncryptUserPassword(string val)
        {
            return new Encrypt().EncryptUserPassword(val);
        }
        /// <summary>
        ///  交易密码加密
        /// </summary>       
        private string YmtEncryptTradingPassword(string val)
        {
            return new Encrypt().EncryptTradingPassword(val);
        }
        /// <summary>
        /// 空凭据
        /// </summary>
        public static readonly UserLoginBill EmptyUserLoginAuth = new UserLoginBill { UserId = -1 };

        protected UserLoginBill()
        {
            //this.UserId = Id;
        }

        protected override IEnumerable<object> CompareValues()
        {
            yield return this.Id;
            yield return this.UserId;
        }
    }
}
